package com.example.chengzhengwei.utils;

import android.util.Log;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;

/**
 * 协议封装和解析
 */
public class SpectrophotometerProtocol {

    // 协议常量
    public static final byte FRAME_HEADER = (byte) 0x55;
    public static final byte FRAME_FOOTER = (byte) 0xAA;
    public static final byte PC_ADDRESS = 0x00;  // 上位机默认地址
    public static final byte DEVICE_ADDRESS = 0x09; // 下位机默认地址

    // 命令字定义
    public static final byte CMD_SELF_CHECK = 0x01;
    public static final byte CMD_READ_VERSION = 0x02;
    public static final byte CMD_SET_PARAMS = 0x03;
    public static final byte CMD_START_EXP = 0x04;
    public static final byte CMD_READ_TEMP_FLUOR = 0x05;
    public static final byte CMD_STOP_EXP = 0x06;
    public static final byte CMD_SOFTWARE_UPGRADE = 0x70;
    public static final byte CMD_SOFTWARE_UPGRADE_END = 0x71;

    // 响应命令字
    public static final byte RESP_SELF_CHECK = (byte) 0x81;
    public static final byte RESP_READ_VERSION = (byte) 0x82;
    public static final byte RESP_SET_PARAMS = (byte) 0x83;
    public static final byte RESP_START_EXP = (byte) 0x84;
    public static final byte RESP_EXP_IN_PROGRESS = (byte) 0xF4; //实验进行中，命令无效
    public static final byte RESP_AUTO_UPLOAD = (byte) 0x85;
    public static final byte RESP_EXP_END = (byte) 0x86;
    public static final byte RESP_SOFTWARE_UPGRADE = (byte) 0xF0;
    public static final byte RESP_SOFTWARE_UPGRADE_END = (byte) 0xF1;
    private static String TAG="SpectrophotometerProtocol";


    // 构建基础帧结构（增加地址参数）
    private static byte[] buildFrame(byte address, byte command, byte[] data) {
        // 计算数据长度 = 有效数据长度 + 2 (校验和占2字节)
        int dataLength = (data != null ? data.length : 0) + 2;
        byte[] lengthBytes = {(byte) (dataLength >> 8), (byte) (dataLength & 0xFF)};

        // 计算校验和 (从地址字段到有效数据结束)
        int checksum = (address & 0xFF); // 包括地址字段
        checksum += (command & 0xFF);
        for (byte b : lengthBytes) checksum += (b & 0xFF);
        if (data != null) for (byte b : data) checksum += (b & 0xFF);
        checksum &= 0xFFFF; // 取低16位

        // 构建帧
        ByteArrayBuilder builder = new ByteArrayBuilder();
        builder.append(FRAME_HEADER)
                .append(address)  // 使用传入的地址
                .append(command)
                .append(lengthBytes);
        if (data != null) builder.append(data);
        builder.append((byte) (checksum >> 8))
                .append((byte) (checksum & 0xFF))
                .append(FRAME_FOOTER);

        return builder.toByteArray();
    }

    // ================== 命令构建方法（增加地址参数）==================

    public static byte[] buildSelfCheckCommand(byte address) {
        return buildFrame(address, CMD_SELF_CHECK, null);
    }

    public static byte[] buildReadVersionCommand(byte address) {
        return buildFrame(address, CMD_READ_VERSION, null);
    }

    public static byte[] buildSetParamsCommand(byte address, int temperature, int reactionTime, int samplePeriod) {
        byte[] data = {
                (byte) (temperature & 0xFF), (byte) (temperature >> 8),
                (byte) (reactionTime & 0xFF), (byte) (reactionTime >> 8),
                (byte) (samplePeriod & 0xFF), (byte) (samplePeriod >> 8)
        };
        return buildFrame(address, CMD_SET_PARAMS, data);
    }

    public static byte[] buildStartExperimentCommand(byte address) {
        return buildFrame(address, CMD_START_EXP, null);
    }

    public static byte[] buildReadTempFluorCommand(byte address) {
        return buildFrame(address, CMD_READ_TEMP_FLUOR, null);
    }

    public static byte[] buildStopExperimentCommand(byte address) {
        return buildFrame(address, CMD_STOP_EXP, null);
    }

    public static byte[] buildSoftwareUpgradeCommand(byte address, int frameIndex, byte[] frameData) {
        if (frameData.length != 256) {
            throw new IllegalArgumentException("Frame data must be exactly 256 bytes");
        }
        byte[] data = new byte[258];
        data[0] = (byte) (frameIndex & 0xFF);
        data[1] = (byte) (frameIndex >> 8);
        System.arraycopy(frameData, 0, data, 2, 256);
        return buildFrame(address, CMD_SOFTWARE_UPGRADE, data);
    }

    public static byte[] buildSoftwareUpgradeEndCommand(byte address) {
        return buildFrame(address, CMD_SOFTWARE_UPGRADE_END, null);
    }

    // ================== 响应解析方法 ==================

    public static Response parseResponse(byte[] frame) throws ProtocolException {
        Log.d("SerialApp-SpectrophotometerProtocol", "<=: "+HexUtils.printHexV2(frame));
        // 基础验证
        if (frame == null || frame.length < 8) {
            throw new ProtocolException("Frame too short");
        }
        if (frame[0] != FRAME_HEADER || frame[frame.length - 1] != FRAME_FOOTER) {
            throw new ProtocolException("Invalid frame boundaries");
        }

        // 不再检查固定设备地址，因为可能有多个设备
        // if (frame[1] != DEVICE_ADDRESS) {
        //     throw new ProtocolException("Invalid device address");
        // }

        // 提取地址和命令字
        byte address = frame[1];
        byte command = frame[2];

        // 提取数据长度
        int dataLength = ((frame[3] & 0xFF) << 8) | (frame[4] & 0xFF);
        int actualDataLength = dataLength - 2; // 减去校验和长度

        //确保帧长度足够，实际会收到残缺数据。
        // 计算最小所需长度：帧头(1) + 地址(1) + 命令(1) + 长度(2) + 有效数据(actualDataLength) + 校验和(2) + 帧尾(1)
        int minRequiredLength = 1 + 1 + 1 + 2 + actualDataLength + 2 + 1;

        if (frame.length < minRequiredLength) {
//            throw new ProtocolException(String.format(
//                    "Frame length insufficient. Required: %d, Actual: %d",
//                    minRequiredLength, frame.length
//            ));
            Log.e(TAG, "Frame length insufficient. Required:"+minRequiredLength+"Actual:"+frame.length +"!!!");
            return new Response(address,command,new byte[0]);
        }



        // 校验和验证（从地址字段开始计算）
        int calculatedChecksum = 0;
        int receivedChecksum = ((frame[frame.length - 3] & 0xFF) << 8) | (frame[frame.length - 2] & 0xFF);

        // 计算校验和 (从命令字段开始到有效数据结束)
        for (int i = 2; i < 5 + actualDataLength; i++) { // 从命令字段开始
            calculatedChecksum += (frame[i] & 0xFF);
        }
        calculatedChecksum &= 0xFFFF;

        if (calculatedChecksum != receivedChecksum) {
            throw new ProtocolException("Checksum mismatch: " +
                    String.format("Expected %04X, Got %04X", calculatedChecksum, receivedChecksum));
        }

        // 提取有效数据
        byte[] data = null;
        if (actualDataLength > 0) {
            data = Arrays.copyOfRange(frame, 5, 5 + actualDataLength);
        }

        return new Response(address, command, data);
    }

    // ================== 辅助类 ==================

    public static class Response {
        private final byte address;
        private final byte command;
        private final byte[] data;

        public Response(byte address, byte command, byte[] data) {
            this.address = address;
            this.command = command;
            this.data = data;
        }

        public byte getAddress() {
            return address;
        }

        public byte getCommand() {
            return command;
        }

        public byte[] getData() {
            return data;
        }

        // 自检响应解析
        public boolean isSelfCheckSuccessful() {
            if (command != RESP_SELF_CHECK) {
                throw new IllegalStateException("Not a self-check response");
            }
            return data != null && data.length > 0 && data[0] == 0x00;
        }

        // 版本号响应解析
        public String getVersionString() {
            if (command != RESP_READ_VERSION) {
                throw new IllegalStateException("Not a version response");
            }
            return new String(data, StandardCharsets.US_ASCII);
        }

        // 温度荧光数据解析
        public TemperatureFluorData getTemperatureFluorData() throws ProtocolException {
            if (command != RESP_AUTO_UPLOAD) {
                throw new IllegalStateException("Not a temperature/fluor response");
            }
            if (data == null || data.length < 20) {
                throw new ProtocolException("Invalid data length for temperature/fluor");
            }

            int uploadCount = (data[0] & 0xFF) | ((data[1] & 0xFF) << 8);
            int temperature = (data[2] & 0xFF) | ((data[3] & 0xFF) << 8);

            int[] fluorValues = new int[8];
            for (int i = 0; i < 8; i++) {
                int offset = 4 + i * 2;
                fluorValues[i] = (data[offset] & 0xFF) | ((data[offset + 1] & 0xFF) << 8);
            }

            return new TemperatureFluorData(uploadCount, temperature, fluorValues);
        }

        // 软件升级响应解析
        public int getUpgradeFrameIndex() {
            if (command != RESP_SOFTWARE_UPGRADE) {
                throw new IllegalStateException("Not a software upgrade response");
            }
            return (data[0] & 0xFF) | ((data[1] & 0xFF) << 8);
        }

        // 设置参数响应解析
        public boolean isSetParamsSuccessful() {
            if (command != RESP_SET_PARAMS) {
                throw new IllegalStateException("Not a set parameters response");
            }
            return data == null; // 协议中无数据，表示成功
        }

        // 开始实验响应解析
        public boolean isStartExperimentSuccessful() {
            if (command != RESP_START_EXP && command != RESP_EXP_IN_PROGRESS) {
                throw new IllegalStateException("Not a start experiment response");
            }
            return command == RESP_START_EXP; // 0x84 成功，0xF4 失败
        }

        // 实验结束响应解析
        public boolean isExperimentEndSuccessful() {
            if (command != RESP_EXP_END) {
                throw new IllegalStateException("Not an experiment end response");
            }
            return data == null; // 协议中无数据，表示成功
        }

        // 软件升级结束响应解析
        public boolean isSoftwareUpgradeEndSuccessful() {
            if (command != RESP_SOFTWARE_UPGRADE_END) {
                throw new IllegalStateException("Not a software upgrade end response");
            }
            return data == null; // 协议中无数据，表示成功
        }


    }

    public static class TemperatureFluorData {
        //上传次数
        private final int uploadCount;

        public int getTemperature() {
            return temperature;
        }

        private final int temperature; // 实际值 = value / 100
        private final int[] fluorValues; // 8个通道的荧光值

        public TemperatureFluorData(int uploadCount, int temperature, int[] fluorValues) {
            this.uploadCount = uploadCount;
            this.temperature = temperature;
            this.fluorValues = fluorValues;
        }

        public double getActualTemperature() {
            return temperature / 100.0;
        }


        public int getUploadCount() {
            return uploadCount;
        }

        public int getFluorValue(int channel) {
            if (channel < 1 || channel > 8) {
                throw new IllegalArgumentException("Channel must be 1-8");
            }
            return fluorValues[channel - 1];
        }
    }

    public static class ProtocolException extends Exception {
        public ProtocolException(String message) {
            super(message);
        }
    }

    // 辅助类：字节数组构建器
    private static class ByteArrayBuilder {
        private byte[] buffer = new byte[32];
        private int size = 0;

        public ByteArrayBuilder append(byte b) {
            ensureCapacity(size + 1);
            buffer[size++] = b;
            return this;
        }

        public ByteArrayBuilder append(byte[] bytes) {
            ensureCapacity(size + bytes.length);
            System.arraycopy(bytes, 0, buffer, size, bytes.length);
            size += bytes.length;
            return this;
        }

        private void ensureCapacity(int minCapacity) {
            if (minCapacity > buffer.length) {
                int newCapacity = Math.max(buffer.length * 2, minCapacity);
                buffer = Arrays.copyOf(buffer, newCapacity);
            }
        }

        public byte[] toByteArray() {
            return Arrays.copyOf(buffer, size);
        }
    }

//    public static void main(String[] args) {
        /*
        // 使用默认地址构建命令
        byte[] selfCheckCmd = buildSelfCheckCommand(PC_ADDRESS);
        byte[] readVersionCmd = buildReadVersionCommand(PC_ADDRESS);
        byte[] setParamsCmd = buildSetParamsCommand(PC_ADDRESS, 6300, 600, 10000);
        byte[] startExpCmd = buildStartExperimentCommand(PC_ADDRESS);
        printHex(selfCheckCmd);
        printHex(readVersionCmd);
        printHex(setParamsCmd);
        printHex(startExpCmd);
        // 使用不同地址构建命令
        byte customAddress = 0x0A; // 自定义设备地址
        byte[] customCmd = buildSelfCheckCommand(customAddress);
        System.out.println("\nCustom address command:");
        printHex(customCmd);
        */
                                                            //55 01 85 00 16 00 00 9C 18 10 27 74 27 D8 27 3C 28 A0 28 04 29 68 29 CC 29 05 FF AA
                                                            //55 09 85 00 16 DD 1B 13 10 E8 03 E8 03 E8 03 86 C3 F6 B1 AA
//        byte[] receivedData = HexUtils.hexStringToByteArray("55 09 85 00 16 DD 1B 13 10 E8 03 E8 03 E8 03 86 C3 F6 B1 AA");
//        try {
//            Response response = SpectrophotometerProtocol.parseResponse(receivedData);
//            if (response.getCommand() == SpectrophotometerProtocol.RESP_AUTO_UPLOAD) {
//                TemperatureFluorData data = response.getTemperatureFluorData();
//                // 获取实际温度值
//                double actualTemp = data.getActualTemperature();
//                System.out.printf("当前温度: %.2f℃%n", actualTemp);
//                // 获取原始温度值（放大100倍的整数值）
//                int rawTemp = data.getTemperature();
//                System.out.println("原始温度值: " + rawTemp);
//
//                for(int i=1;i<=8;i++){
//                    System.out.println(i+" "+data.getFluorValue(i));
//                }
//            }
//        } catch (ProtocolException e) {
//            e.printStackTrace();
//        }
//    }


}